package cn.cocho.android.mc.comp.listview;

import java.text.MessageFormat;
import java.util.Date;

import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

import cn.cocho.android.mc.R;
import cn.cocho.android.mc.base.ResourcesUtils;
import cn.cocho.android.mc.comp.util.SlidingMenuView;
import cn.cocho.android.mc.log.LoggerUtils;
import cn.cocho.android.mc.util.DateUtil;

public class McListView extends ListView {

	private int pageSize;
	private int pullDownMaxHeight;
	private Drawable arrowUpImg;
	private Drawable arrowDownImg;
	private Drawable loadingImg;
	private View emptyView;
	private String loadingText;

	private View headerView;
	public View footerView;
	private RotateAnimation pullDownAnim;
	private RotateAnimation releaseAnim;
	private RotateAnimation loadingAnim;
	private int headerHeight;
	private OnStateChangeListener onStateChangeListener;

	private Context context;
	private Date lastUpdateTime = new Date();

	private float startY;
	private float currentY;
	public State currentState = State.DONE;

	/**
	 * 是否启用下拉刷新
	 */
	private boolean pullDownRefreshAble = true;

	private SlidingMenuView slidingMenuView;

	public enum State {
		DONE, PULL_DOWN_ING, RELEASE, LOADING, CANCEL
	}

	public McListView(Context context) {
		super(context);
		this.context = context;
	}

	public McListView(Context context, AttributeSet attrs) {
		super(context, attrs);
		this.context = context;
		init(context, attrs);
	}

	public McListView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		this.context = context;
		init(context, attrs);
	}

	private void init(Context context, AttributeSet attrs) {
		initListView(context, attrs);
		initHeaderView();
		initFooterView();
		initAnim();
	}

	// private void initListView() {
	// Resources resources = getResources();
	// pageSize = attrs.getAttributeIntValue(CompUtils.NS_TBC, PAGE_SIZE, 10);
	// pullDownMaxHeight = attrs.getAttributeIntValue(CompUtils.NS_TBC,
	// PULLDOWN_MAXHEIGHT, 10);
	// arrowUpImg =
	// resources.getDrawable(attrs.getAttributeResourceValue(CompUtils.NS_TBC,
	// ARROWUP_IMG, 0));
	// arrowDownImg =
	// resources.getDrawable(attrs.getAttributeResourceValue(CompUtils.NS_TBC,
	// ARROWDOWN_IMG, 0));
	// loadingImg =
	// resources.getDrawable(attrs.getAttributeResourceValue(CompUtils.NS_TBC,
	// LOADING_IMG, 0));
	// LayoutInflater inflater = (LayoutInflater)
	// ApplicationCache.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
	// emptyView =
	// inflater.inflate(attrs.getAttributeResourceValue(CompUtils.NS_TBC,
	// EMPTY_VIEW, 0), null);
	// loadingText = resources.getString(R.string.listview_refreshing);
	// }

	private void initListView(Context context, AttributeSet attrs) {
		TypedArray tdarr = context.obtainStyledAttributes(attrs, R.styleable.McListView);
		pageSize = tdarr.getInteger(R.styleable.McListView_listView_pageSize, 10);
		pullDownMaxHeight = tdarr.getInteger(R.styleable.McListView_listView_pullDownMaxHeight, 10);
		arrowUpImg = tdarr.getDrawable(R.styleable.McListView_listView_arrowUpImg);
		arrowDownImg = tdarr.getDrawable(R.styleable.McListView_listView_arrowDownImg);
		loadingImg = tdarr.getDrawable(R.styleable.McListView_listView_loadingImg);
		LayoutInflater inflater = LayoutInflater.from(context);
		int resId = tdarr.getResourceId(R.styleable.McListView_listView_emptyView, R.layout.mc_list_view_empty);
		emptyView = inflater.inflate(resId, null);
		Resources resources = getResources();
		loadingText = resources.getString(R.string.listview_refreshing);
		tdarr.recycle();
	}

	private void initHeaderView() {
		LayoutInflater inflater = LayoutInflater.from(context);
		headerView = inflater.inflate(R.layout.mc_list_view_header, null);
		headerView.setPadding(0, -1 * headerHeight, 0, 0);// 初始化的时候应该隐藏头部加载信息
		headerView.setVisibility(View.INVISIBLE);
		addHeaderView(headerView, null, false);
	}

	private void initFooterView() {
		LayoutInflater inflater = LayoutInflater.from(context);
		footerView = inflater.inflate(R.layout.mc_list_view_footer, null);
		addFooterView(footerView, null, false);
	}

	private void initAnim() {
		pullDownAnim = new RotateAnimation(0, -180, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);
		pullDownAnim.setInterpolator(new LinearInterpolator());
		pullDownAnim.setDuration(300);
		pullDownAnim.setFillAfter(true);

		releaseAnim = new RotateAnimation(-180, 0, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);
		releaseAnim.setInterpolator(new LinearInterpolator());
		releaseAnim.setDuration(300);
		releaseAnim.setFillAfter(true);

		loadingAnim = new RotateAnimation(0, 360, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);
		loadingAnim.setInterpolator(new LinearInterpolator());
		loadingAnim.setDuration(1200);
		loadingAnim.setRepeatCount(Animation.INFINITE);
		loadingAnim.setRepeatMode(RotateAnimation.RESTART);

	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		if (headerHeight == 0) {
			if (headerView != null) {
				headerView.measure(headerView.getWidth(), headerView.getHeight());
				headerHeight = headerView.getMeasuredHeight();
				if (currentState == State.DONE) {
					headerView.setPadding(0, -1 * headerHeight, 0, 0);
				}
			}
		}
	}

	@Override
	public boolean onTouchEvent(MotionEvent ev) {
		if (!isPullDownRefreshAble()) {
			return super.onTouchEvent(ev);
		}

		if (slidingMenuView != null && slidingMenuView.isOpen()) {
			return super.onTouchEvent(ev);
		}

		int action = ev.getAction();
		currentY = ev.getY();
		switch (action) {
		case MotionEvent.ACTION_DOWN:
			if (getFirstVisiblePosition() != 0 || currentState == State.LOADING) {// listview
																					// 的第一条
																					// 在屏幕的最上面
				break;
			}

			currentState = State.DONE;
			startY = currentY;
			headerView.setVisibility(View.VISIBLE);
			updateLastUpdateTime();
			return true;
		case MotionEvent.ACTION_MOVE:
			if (!(getFirstVisiblePosition() == 0) || startY == 0 || currentState == State.LOADING) {
				break;
			}
			/**
			 * 如果当前的触摸点的Y坐标 小于起始的Y坐标，则取消本次操作
			 */
			if (currentY < startY) {
				updateState(State.CANCEL);
				break;
			}
			/**
			 * 计算滑动的距离
			 */
			float moveDistance = currentY - startY;
			// 当前状态是释放状态
			if (currentState == State.RELEASE) {
				if (moveDistance < pullDownMaxHeight) {
					// 则更新当前的状态为下拉中
					updateState(State.PULL_DOWN_ING);
				} else {
					// 更新当前的状态为释放状态
					updateState(State.RELEASE);
				}
				return true;
			} else if (currentState == State.PULL_DOWN_ING) {
				if (moveDistance >= pullDownMaxHeight) {
					// 设置当前的状态为 释放 状态
					updateState(State.RELEASE);
				} else {
					// 设置当前的状态为下拉状态
					updateState(State.PULL_DOWN_ING);
				}
				return true;
			} else if (currentState == State.DONE) {
				// 设置状态为 下拉状态
				updateState(State.PULL_DOWN_ING);
				return true;
			}
			break;
		// 手放开的时候
		case MotionEvent.ACTION_UP:
			if (getFirstVisiblePosition() != 0) {// 也就是说 listview 的第一条 不在屏幕的最上面
				break;
			}
			if (currentState == State.LOADING || currentState == State.CANCEL) {
				startY = 0;
				break;
			}
			if (currentState == State.RELEASE) {
				moveListView(currentY);
				return true;
			} else {
				updateState(State.CANCEL);
			}
		}

		try {
			return super.onTouchEvent(ev);
		} catch (Exception e) {
			LoggerUtils.error(McListView.class.getName(), "自定义TbcListView中监听触摸事件时出错", e);
			return false;
		}

	}

	public void updateState(State newState) {
		updateHeader(newState);
		if (currentState != newState) {
			updateView(newState);
			currentState = newState;
		}
	}

	private void updateHeader(State newState) {
		if (newState == State.PULL_DOWN_ING) {
			int topPadding = getTopPadding();
			headerView.setPadding(0, topPadding, 0, 0);
		} else if (newState == State.RELEASE) {
			int topPadding = getTopPadding();
			headerView.setPadding(0, topPadding, 0, 0);
		} else if (newState == State.LOADING) {
			headerView.setVisibility(View.VISIBLE);
			headerView.setPadding(0, 0, 0, 0);
		} else if (newState == State.DONE) {
			headerView.setPadding(0, -1 * headerHeight, 0, 0);
			headerView.setVisibility(View.INVISIBLE);
			lastUpdateTime = new Date();
		} else if (newState == State.CANCEL) {
			headerView.setVisibility(View.INVISIBLE);
			headerView.setPadding(0, -1 * headerHeight, 0, 0);
		}
	}

	public void updateFooter(String msg, boolean isRemove) {
		TextView tv_more = (TextView) footerView.findViewById(R.id.list_view_footer_more);
		tv_more.setText(msg);
		if (isRemove) {
			removeFooterView(footerView);
		} else {
			if (getFooterViewsCount() == 0) {
				addFooterView(footerView);
			}
		}
	}

	private int getTopPadding() {
		int f = (int) ((currentY - startY) / 2);
		int topPadding = -1 * (headerHeight - f);
		return topPadding;
	}

	private void updateView(State newState) {
		TextView refreshTip = (TextView) findViewById(R.id.list_view_header_refreshTips);
		ImageView imageIcon = (ImageView) findViewById(R.id.list_view_header_arrowDownIcon);
		imageIcon.clearAnimation();
		switch (newState) {
		case PULL_DOWN_ING:
			if (currentState == State.RELEASE) {
				imageIcon.startAnimation(releaseAnim);
			} else {
				imageIcon.setImageDrawable(arrowDownImg);
			}
			refreshTip.setText(ResourcesUtils.getString(R.string.listview_pull_down_refresh));
			break;
		case RELEASE:
			imageIcon.setImageDrawable(arrowUpImg);
			imageIcon.startAnimation(releaseAnim);
			refreshTip.setText(ResourcesUtils.getString(R.string.listview_release_refresh));
			break;
		case LOADING:
			imageIcon.setImageDrawable(loadingImg);
			imageIcon.startAnimation(loadingAnim);
			refreshTip.setText(loadingText);
			break;
		default:
			break;
		}
	}

	int padding = getTopPadding();
	int sleepTime = 35;// 滑动一段距离后的休眠时间（单位为毫秒）
	int movePixel = 25;// 每次移动的像素点数

	private void moveListView(final float currentYCoodinate) {
		final Handler handler = new Handler();
		handler.postDelayed(new Runnable() {
			@Override
			public void run() {
				padding = padding - movePixel;
				if (padding <= 0) {
					padding = 0;
				}
				headerView.setPadding(0, padding, 0, 0);// 这句话是指，listview的头部view的top距离父控件的底部距离

				/**
				 * 下面这段代码的意思是当padding大于0时，一直执行run中的内容，直到padding小于等于0，由于上面做了判读
				 * 当padding小于0时，会直接变成0；所以当padding等于0时，才执行else中的代码
				 * 
				 */
				if (padding > 0) {
					handler.postDelayed(this, sleepTime);
				} else {
					updateState(State.LOADING);
					if (onStateChangeListener != null) {
						onStateChangeListener.stateChanged(McListView.this, State.LOADING);
					}
				}
			}
		}, sleepTime);
	}

	private void updateLastUpdateTime() {
		TextView refreshTip = (TextView) findViewById(R.id.list_view_header_lastSyncTime);
		String lastSyncTime = DateUtil.formatDateSpace(lastUpdateTime);
		String lastSyncMsg = ResourcesUtils.getString(R.string.listview_lastSyncTime);
		lastSyncMsg = MessageFormat.format(lastSyncMsg, lastSyncTime);
		refreshTip.setText(lastSyncMsg);
	}

	public interface OnStateChangeListener {
		public void stateChanged(McListView listView, State newState);
	}

	public OnStateChangeListener getOnStateChangeListener() {
		return onStateChangeListener;
	}

	public void setOnStateChangeListener(OnStateChangeListener onStateChangeListener) {
		this.onStateChangeListener = onStateChangeListener;
	}

	public int getPageSize() {
		return pageSize;
	}

	public void setPageSize(int pageSize) {
		this.pageSize = pageSize;
	}

	public int getPullDownMaxHeight() {
		return pullDownMaxHeight;
	}

	public void setPullDownMaxHeight(int pullDownMaxHeight) {
		this.pullDownMaxHeight = pullDownMaxHeight;
	}

	public Drawable getArrowTopImg() {
		return arrowUpImg;
	}

	public void setArrowTopImg(Drawable arrowTopImg) {
		this.arrowUpImg = arrowTopImg;
	}

	public Drawable getArrowDownImg() {
		return arrowDownImg;
	}

	public void setArrowDownImg(Drawable arrowDownImg) {
		this.arrowDownImg = arrowDownImg;
	}

	public Drawable getLoadingImg() {
		return loadingImg;
	}

	public void setLoadingImg(Drawable loadingImg) {
		this.loadingImg = loadingImg;
	}

	public View getEmptyView() {
		return emptyView;
	}

	public void setEmptyView(View emptyView) {
		this.emptyView = emptyView;
	}

	public String getLoadingText() {
		return loadingText;
	}

	public void setLoadingText(String loadingText) {
		this.loadingText = loadingText;
	}

	public boolean isPullDownRefreshAble() {
		return pullDownRefreshAble;
	}

	public void setPullDownRefreshAble(boolean pullDownRefreshAble) {
		this.pullDownRefreshAble = pullDownRefreshAble;
	}

	public void setSlidingMenuView(SlidingMenuView slidingMenuView) {
		this.slidingMenuView = slidingMenuView;
	}

}
